package proyectotsm;

import java.awt.image.BufferedImage;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.zip.*;
import javax.imageio.ImageIO;
import javax.swing.JTextArea;

/**
 * Clase Lector.java
 *
 * @author Juancarlos
 * @author Srgank
 * @author Gabriel
 */
class Lector {

    // Atributos
    private String ruta;
    private static ArrayList<Imagen> imagenes;
    private int anchoteselas;
    private int altoteselas;
    private int factorCompresion;
    private int recur;
    private int rango;

    /**
     * Clase que carga un fichero .zip lleno de imagenes
     * @param ruta: ruta donde se halla el fichero .zip a cargar
     */
    public Lector(String ruta) {
        anchoteselas = 30;
        altoteselas = 30;
        factorCompresion = 30;
    }

    /**
     * Constructor sin parametros
     */
    public Lector() {
        anchoteselas = 30;
        altoteselas = 30;
        factorCompresion = 30;
    }

    /**
     * Configura el alto de la tesela
     *
     * @param altoteselas El alto de la tesela
     */
    public void setAltoteselas(int altoteselas) {
        this.altoteselas = altoteselas;
    }

    /**
     * Configura el parametro de compresion
     *
     * @param factorCompresion El parametro de compresion
     */
    public void setFactorCompresion(int factorCompresion) {
        this.factorCompresion = factorCompresion;
    }

    /**
     * Configura el ancho de las teselas
     *
     * @param anchoteselas El ancho de las teselas
     */
    public void setAnchoteselas(int anchoteselas) {
        this.anchoteselas = anchoteselas;
    }

    /**
     * Configura el numero de vueltas
     *
     * @param recur El numero de vueltas
     */
    public void setRecur(int recur) {
        this.recur = recur;
    }

    /**
     * Configura el rango de compresion
     *
     * @param rango El rango de compresion
     */
    public void setRango(int rango) {
        this.rango = rango;
    }

    /**
     * Metodo que setea el archivo que queremos cargar
     *
     * @param ruta: Ruta del fichero a cargar
     */
    public void setArchivo(String ruta) {
        this.ruta = ruta;
        imagenes = new ArrayList<Imagen>();
    }

    /**
     * Metodo que carga las imagenes del archivo
     *
     * @param output: Lugar donde sera representada la salida de la carga de imagenes
     * @return retorna 1 si la carga fue bien y 0 si fue mal
     * @throws FileNotFoundException : excepcion por  no haber encontrado el fichero
     * @throws IOException: excepcion por no poder leer el fichero
     */
    public int cargarImagenes(JTextArea output) {
        ArrayList<Ocurrencia> ocurrencias = new ArrayList();
        ZipEntry entrada;
        int contador = 0;
        String archTemp = "temp.jpg";
        FileInputStream fis = null;
        int numero = 0;
        try {
            fis = new FileInputStream(ruta);
        } catch (FileNotFoundException ex) {
            Logger.getLogger(Lector.class.getName()).log(Level.SEVERE, null, ex);
            System.out.println("Error al abrir el Steam de entrada");
            output.append("Error al abrir el Steam de entrada");
        }
        ZipInputStream zis = new ZipInputStream(new BufferedInputStream(fis));
        BufferedOutputStream dest = null;
        byte[] data = new byte[9000];
        try {
            // Leemos secuencialmente el archivo zip
            while ((entrada = zis.getNextEntry()) != null) {
                File bufferTemporal = new File(archTemp);
                System.out.println("Archivo " + entrada.getName() + " cargado!");
                output.append("Archivo " + entrada.getName() + " cargado!\n");
                if (entrada.getName().endsWith(".txt")) {
                    anchoteselas = zis.read();
                    altoteselas = zis.read();
                    int nImagenes = zis.read();
                    int digitos = zis.read();
                    int totalOcurrencias = 0;

                    for (int i = 0; i < digitos; i++) {
                        totalOcurrencias = totalOcurrencias * 10 + zis.read();
                    }
                    System.out.println("nImagenes:" + nImagenes);
                    for (int i = 0; i < totalOcurrencias; i++) {
                        Ocurrencia ocurrencia = new Ocurrencia(zis.read(), zis.read(), zis.read(), zis.read(), zis.read());
                        ocurrencias.add(ocurrencia);
                        System.out.println(ocurrencia);
                    }

                } else if (!entrada.isDirectory()) {
                    FileOutputStream fos = new FileOutputStream(bufferTemporal);
                    dest = new BufferedOutputStream(fos, 9000);
                    while ((contador = zis.read(data, 0, 9000)) != -1) {
                        dest.write(data, 0, contador);
                    }
                    //Cerramos los buffers
                    dest.flush();
                    dest.close();
                    fos.flush();
                    fos.close();
                    java.io.FileInputStream fin = new FileInputStream(bufferTemporal);
                    BufferedImage bi = ImageIO.read(fin);
                    //Guardamos el fichero
                    imagenes.add(new Imagen(bi, entrada.getName().substring(0, entrada.getName().lastIndexOf(".")), numero));
                    numero++;
                }
                bufferTemporal.delete();
            }
        } catch (IOException ex) {
            Logger.getLogger(Lector.class.getName()).log(Level.SEVERE, null, ex);
            System.out.println("Error al cargar los ficheros");
        }
        try {
            fis.close();
            zis.close();

            dest.flush();
            dest.close();
        } catch (IOException ex) {
            Logger.getLogger(Lector.class.getName()).log(Level.SEVERE, null, ex);
            System.out.println("Error cerrando el input Steam");
        }

        System.out.println("Archivos cargados con exito!");
        output.append("Archivos cargados con exito!");

        sort();

        if (!ocurrencias.isEmpty()) {
            System.out.println(ocurrencias.size());
            System.out.println("Descomprimiendo");
            Compresor com = new Compresor(imagenes, anchoteselas, altoteselas, factorCompresion, recur, rango);
            com.setearParametros();
            imagenes = com.decomprimir(ocurrencias, anchoteselas, altoteselas);
        }
        return 1;
    }

    /**
     * Ordenamos la lista de imagenes
     */
    private void sort() {
        int n = imagenes.size();
        for (int inc = 1; inc < n; inc++) {
            for (int i = 0; i < n - inc; i++) {
                Imagen imagen1 = (Imagen) imagenes.toArray()[i];
                Imagen imagen2 = (Imagen) imagenes.toArray()[i + 1];

                if (imagen1.getNombre().compareTo(imagen2.getNombre()) > 0) {
                    Collections.swap((List<Imagen>) imagenes, i, i + 1);
                }
            }
        }
    }

    /**
     * Funcion que retorna el array de peliculas
     * @return retorna el array de peliculas
     */
    public Collection<Imagen> getImagenes() {
        return imagenes;
    }

    /**
     * Guardamos el archivo con el nuevo formato de compresion
     *
     * @param pathzip El archivo de salida
     * @param comprimir El tipo de compresion que efectuamos
     */
    public void saveNewCompress(String pathzip, boolean comprimir) {
        int num = 1;
        Collection<Ocurrencia> ocurrencias = null;
        Iterator Iocurrencia = null;
        int nImagenes = 0;

        if (comprimir) {     
            
            Compresor compresor = new Compresor(imagenes, anchoteselas, altoteselas, factorCompresion, recur, rango);
            compresor.setearParametros();
            
            ArrayList[] returns = compresor.comprimir();
            imagenes = returns[0];
            nImagenes = imagenes.size();
            ocurrencias = returns[1];
            Iocurrencia = ocurrencias.iterator();
        }
        
        Iterator i = imagenes.iterator();
        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream(pathzip.substring(0, pathzip.lastIndexOf(".")) + ".DOF");
        } catch (FileNotFoundException ex) {
            Logger.getLogger(Lector.class.getName()).log(Level.SEVERE, null, ex);
            System.out.println("Error abriendo el fichero de salida");
        }
        ZipOutputStream zos = new ZipOutputStream(fos);

        try {
            Imagen tmp = (Imagen) i.next();
            BufferedImage img = tmp.getBufferedImagen();

            ZipEntry ze = new ZipEntry(tmp.getNombre() + ".JPEG");

            zos.putNextEntry(ze);
            ImageIO.write(img, "JPEG", zos);

            System.out.println("Archivo" + tmp.getNombre() + " Guardado en JPEG");
            zos.closeEntry();

            zos.flush();

            while (i.hasNext()) {

                tmp = (Imagen) i.next();
                img = tmp.getBufferedImagen();
                ze = new ZipEntry(tmp.getNombre() + ".JPEG");

                zos.putNextEntry(ze);
                ImageIO.write(img, "JPEG", zos);
                System.out.println("Archivo" + tmp.getNombre() + " Guardado en JPEG");
                zos.closeEntry();

                zos.flush();

                num++;
            }
            if (comprimir) {
                ze = new ZipEntry("teselas.txt");
                zos.putNextEntry(ze);
                zos.write(anchoteselas);
                zos.write(altoteselas);
                zos.write(nImagenes);

                String noc = String.valueOf(ocurrencias.size());
                int digitos = String.valueOf(ocurrencias.size()).length();
                zos.write(digitos);
                for (int d = 0; d < digitos; d++) {
                    System.out.println("ecribo:" + Integer.parseInt(String.valueOf(noc.charAt(d))));
                    zos.write(Integer.parseInt(String.valueOf(noc.charAt(d))));

                }
                System.out.println("Ocurrencias:" + ocurrencias.size());
                while (Iocurrencia.hasNext()) {
                    Ocurrencia ocurrencia = (Ocurrencia) Iocurrencia.next();
                    zos.write(ocurrencia.getnTeselaX());
                    zos.write(ocurrencia.getnTeselaY());
                    zos.write(ocurrencia.getPosX());
                    zos.write(ocurrencia.getPosY());
                    zos.write(ocurrencia.getNumero());
                }             
                
                imagenes.clear();            
            }
            zos.close();
        } catch (IOException io) {
            Logger.getLogger(Lector.class.getName()).log(Level.SEVERE, null, io);
            System.out.println("Error guardando los ficheros");
        }
        System.out.println("anchotesela: " + anchoteselas + " altoteselas: " + altoteselas);
    }
}
